package com.dongdongqiang.daogenerator.handler.impl;

import com.dongdongqiang.daogenerator.exception.DDQException;
import com.dongdongqiang.daogenerator.handler.IQueryHandler;
import com.dongdongqiang.daogenerator.pojo.TableColumn;
import com.dongdongqiang.daogenerator.pojo.TableMeta;
import com.dongdongqiang.daogenerator.sqlbuilder.QuerySQLBuilder;
import com.dongdongqiang.daogenerator.utils.POJOUtils;
import com.dongdongqiang.daogenerator.tablemetabuilder.TableMetaBuilderImpl;

import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by ZZB on 2017/10/22.
 */
public class QueryHandlerImpl implements IQueryHandler {
    private QuerySQLBuilder querySQLBuilder;

    public QueryHandlerImpl(QuerySQLBuilder querySQLBuilder) {
        this.querySQLBuilder = querySQLBuilder;
    }

    @Override
    public <T> T getBy(Object pk, Class<T> tClass, Connection connection) {
        TableMeta tableMeta = TableMetaBuilderImpl.obtainByClass(tClass);
        return findBy(tableMeta.getPrimaryKeyColumn().getColumnName(),pk,tClass,connection);
    }

    @Override
    public <T> T findBy(String c, Object o, Class<T> tClass, Connection connection) {
        TableColumn tableColumn = TableMetaBuilderImpl.obtainByFieldName(tClass, c);
        if(tableColumn != null){
            c = tableColumn.getColumnName();
        }

        List<T> list = queryBy(c, o, tClass, connection);
        if(list != null && list.size() > 0){
            return list.get(0);
        }
        return null;
    }

    @Override
    public <T> List<T> queryBy(String c, Object o, Class<T> tClass, Connection connection) {
        TableColumn tableColumn = TableMetaBuilderImpl.obtainByFieldName(tClass, c);
        if(tableColumn != null){
            c = tableColumn.getColumnName();
        }

        TableMeta tableMeta = TableMetaBuilderImpl.obtainByClass(tClass);
        String sql = querySQLBuilder.queryByFieldSQL(tableMeta.getTableName(), c);
        return query(sql,tClass,new Object[]{o},connection);
    }

    @Override
    public <T> List<T> query(String sql, Class<T> tClass , Connection connection) {
        try {
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            return readFromResultSet(resultSet, tClass);
        } catch (Exception e) {
            throw new DDQException(e);
        }
    }

    @Override
    public <T> List<T> query(String sql, Class<T> tClass ,Object[] objects, Connection connection) {
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < objects.length; i++) {
                preparedStatement.setObject(i+1,objects[i]);
            }
            ResultSet resultSet = preparedStatement.executeQuery();
            return readFromResultSet(resultSet, tClass);
        } catch (Exception e) {
            throw new DDQException(e);
        }
    }

    private <T> List<T> readFromResultSet(ResultSet resultSet,Class<T> tClass) throws SQLException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
        TableMeta tableMeta = TableMetaBuilderImpl.obtainByClass(tClass);
        List<T> list = new ArrayList<>();
        while (resultSet.next()){
            T t = tClass.newInstance();
            List<TableColumn> tableColumns = tableMeta.getTableColumns();
            for (TableColumn tableColumn : tableColumns) {
                String columnName = tableColumn.getColumnName();
                POJOUtils.writeDeclaredFieldBySetMethod(t,tableColumn.getPropertyName(),resultSet.getObject(columnName));
            }
            list.add(t);
        }
        return list;
    }

    private long countFromResultSet(ResultSet resultSet) throws SQLException {
        if (resultSet.next()) {
            return resultSet.getLong(1);
        }
        return 0L;
    }

    @Override
    public long queryCount(String sql, Connection connection) {
        try {
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            return countFromResultSet(resultSet);
        } catch (Exception e) {
            throw new DDQException(e);
        }
    }

    @Override
    public long queryCount(String sql, Object[] objects, Connection connection) {
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < objects.length; i++) {
                preparedStatement.setObject(i+1,objects[i]);
            }
            ResultSet resultSet = preparedStatement.executeQuery();
            return countFromResultSet(resultSet);
        } catch (Exception e) {
            throw new DDQException(e);
        }
    }

    @Override
    public <T> long countBy(String c, Object o, Class<T> tClass, Connection connection) {
        TableColumn tableColumn = TableMetaBuilderImpl.obtainByFieldName(tClass, c);
        if(tableColumn != null){
            c = tableColumn.getColumnName();
        }

        TableMeta tableMeta = TableMetaBuilderImpl.obtainByClass(tClass);
        String sql = querySQLBuilder.countByFieldSQL(tableMeta.getTableName(), c);
        return queryCount(sql,new Object[]{o},connection);
    }
}
